#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>

#define BUF_SIZE 30

int main(int argc, char *argv[])
{
	fd_set reads, temps;
	int result, str_len;
	char buf[BUF_SIZE];
	struct timeval timeout;

	FD_ZERO(&reads);
	FD_SET(0, &reads);               // 0为标准输入

	while(1)
	{
		temps=reads;                      //! 每次都要重新赋值, 不然上次发生超时则该位会被置0
		timeout.tv_sec  = 5;       		  //! 调用select 函数后，结构体timeval的值将被替换为超时前剩余时间。
		timeout.tv_usec = 0;

		/**
		 * @brief  select函数用来验证3种监视项的变化情况，如果在指定超时时间内都没有发生变化, 则返回0
		 * 
		 * @param  int      nfds          监视文件描述符的数量
		 * @param  fd_set   *readfds      将所有关注'是否存在待读取数据'的文件描述符注册到fd_set变量
		 * @param  fd_set   *writefds     将所有关注'是否可传输无阻塞数据'的文件描述符注册到fd_set变量
		 * @param  fd_set   *exceptfds    将所有关注'是否发生异常'的文件描述符注册到fd_set变量
		 * @param  timeval  *timeout      调用select函数后，为防止陷入无限阻塞的状态(即在很长时间内都没有文件描述符状态发生变化)，需要传递超时信息. 如果不想设置超时时间，该参数设置为NULL即可.
		 * 
		 * @return int      发生错误时返回-1， 超时返回0(即在超时的范围内没有文件描述符的状态发生变化)， 因发生关注的事件返回时，返回大于0的值表示发生事件的文件描述符数量
		 */
		// int select (int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout);
		//! 监视一个文件描述符，只传递temps作为监视的输入套接字组
		result = select(1, &temps, 0, 0, &timeout);
		if(result == -1)                          // 发生了错误
		{ 
			puts("select() error!");
			break;
		}
		else if(result==0)                        // 2. 超时了也没有套接字发生变化
		{      
			puts("Time-out!");
		}
		else 
		{
			if(FD_ISSET(0, &temps))               // 3. 有套接字发生了变化
			{
				str_len=read(0, buf, BUF_SIZE);   // 4. 从stdin读取数据
				buf[str_len]=0;
				printf("message from console: %s", buf);
			}
		}
	}
	return 0;
}